package com.ling.rocketmq.producer;


import com.google.gson.Gson;
import com.ling.rocketmq.annotation.Rocketmq;
import com.ling.rocketmq.model.MessageBodyParam;
import org.apache.rocketmq.common.message.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

public class RocketmqProducerProxy<T> implements InvocationHandler, Serializable {
    private static final long serialVersionUID = 1L;

    private final static Logger log = LoggerFactory.getLogger(RocketmqProducerProxy.class);

    private MQProducerFactory producerFactory;

    private Class<T> interfaceClass;

    public RocketmqProducerProxy(Class<T> interfaceClass) {
        this.interfaceClass = interfaceClass;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Rocketmq rocketmq = method.getAnnotation(Rocketmq.class);
        String key = rocketmq.messageKey();
        String tag = rocketmq.tag();
        if (key.contains("#")) {
            //调用SPELExpressionParser方法解析出注解的实际值
            key = generateKeyBySpEL(key, method, args);
        } else {
            key = UUID.randomUUID().toString().replaceAll("-", "");
        }

        if (tag.contains("#")) {
            //调用SPelExpressionParser方法解析出注解的实际值
            tag = generateKeyBySpEL(rocketmq.tag(), method, args);
        }

        Message message = new Message();
        message.setTopic(rocketmq.topic());
        message.setKeys(key);
        message.setTags(tag);

        List<MessageBodyParam> params = new LinkedList<>();

        for (Object arg : args) {
            MessageBodyParam param = new MessageBodyParam();
            param.setClassName(arg.getClass().getName());
            param.setClassValue(new Gson().toJson(arg));
            params.add(param);
        }
        String body = new Gson().toJson(params);
        message.setBody(body.getBytes());
        producerFactory.getProducer().send(message);
        return null;
    }

    public RocketmqProducerProxy<T> setProducerFactory(MQProducerFactory producerFactory) {
        this.producerFactory = producerFactory;
        return this;
    }

    public T getProxy() {
        return (T) Proxy.newProxyInstance(
                interfaceClass.getClassLoader(),
                new Class[]{interfaceClass},
                this);
    }


    /**
     * 用于SpEL表达式解析.
     */
    private final SpelExpressionParser parser = new SpelExpressionParser();
    /**
     * 用于获取方法参数定义名字.
     */
    private final DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();

    private String generateKeyBySpEL(String spELString, Method method, Object[] args) {
        String[] paramNames = nameDiscoverer.getParameterNames(method);
        Expression expression = parser.parseExpression(spELString);
        EvaluationContext context = new StandardEvaluationContext();
        for (int i = 0; i < args.length; i++) {
            assert paramNames != null;
            context.setVariable(paramNames[i], args[i]);
        }
        return Objects.requireNonNull(expression.getValue(context)).toString();
    }

}